package com.cwt.framework.handler;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.cwt.common.enums.BusinessErrorCode;
import com.cwt.common.result.AjaxResult;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.LinkedList;
import java.util.List;

/**
 * @author chenwt
 * @version V1.0
 * @describe 【全局异常拦截】
 * @date 2023年07月17日 14:56:40
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 未登录
     *
     * @param e 异常
     * @return 异常响应封装
     */
    @ExceptionHandler(value = NotLoginException.class)
    public AjaxResult notLoginExceptionHandler(NotLoginException e) {
        errorFixedPosition(e);
        logger.error("_> 错误原因：");
        logger.error("_> {}", e.getMessage());
        logger.error("=============================错误打印完毕=============================");
        return AjaxResult.error(BusinessErrorCode.NO_HAVE_LOGIN_USER);
    }

    /**
     * 角色异常
     *
     * @param e 异常
     * @return 异常响应封装
     */
    @ExceptionHandler(value = {NotRoleException.class, NotPermissionException.class})
    public AjaxResult notRoleExceptionHandler(Exception e) {
        errorFixedPosition(e);
        logger.error("_> 错误原因：");
        logger.error("_> {}", e.getMessage());
        logger.error("=============================错误打印完毕=============================");
        return AjaxResult.error(BusinessErrorCode.NOT_PERMISSION_ERROR);
    }

    /**
     * 捕获全局异常
     *
     * @param e 全局异常
     * @return 常响应封装
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public AjaxResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        LinkedList<String> errors = Lists.newLinkedList();
        if (!CollectionUtils.isEmpty(allErrors)) {
            allErrors.forEach(objectError -> errors.add(objectError.getDefaultMessage()));
        }

        errorFixedPosition(e);
        logger.error("_> 错误原因：");
        logger.error("_> {}", e.getMessage());
        logger.error("=============================错误打印完毕=============================");
        return AjaxResult.error(BusinessErrorCode.ARGS_VALID_ERROR.getCode(), BusinessErrorCode.ARGS_VALID_ERROR.getErrMessage(), errors);
    }

    /**
     * 处理空指针的异常
     *
     * @param e 异常
     * @return 异常响应封装
     */
    @ExceptionHandler(value = NullPointerException.class)
    public AjaxResult exceptionHandler(NullPointerException e) {
        errorFixedPosition(e);
        logger.error("_> 错误原因：");
        logger.error("_> {}", e.getMessage());
        logger.error("=============================错误打印完毕=============================");
        return AjaxResult.error(BusinessErrorCode.SYS_ERROR);
    }

    /**
     * 处理其他异常
     *
     * @param e 参数
     * @return 返回异常信息
     */
    @ExceptionHandler(value = Exception.class)
    public AjaxResult exceptionHandler(Exception e) {
        errorFixedPosition(e);
        logger.error("_> 错误原因：");
        logger.error("_> {}", e.getMessage());
        logger.error("=============================错误打印完毕=============================");
        return AjaxResult.error(BusinessErrorCode.SYS_ERROR);
    }

    /**
     * 定位错误发生的位置
     *
     * @param e 错误参数
     */
    private void errorFixedPosition(Exception e) {
        final StackTraceElement stackTrace = e.getStackTrace()[0];
        final String className = stackTrace.getClassName();
        final int lineNumber = stackTrace.getLineNumber();
        final String methodName = stackTrace.getMethodName();
        e.printStackTrace();
        logger.error("=============================错误信息如下=============================");
        logger.error("_> 异常定位：");
        logger.error("_> 类[{}] ==> 方法[{}] ==> 所在行[{}]\n", className, methodName, lineNumber);
    }

}

